package dancrawler.client;

import dancrawler.sound.SoundBank;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;

public class GamePanel extends JComponent implements GameListener, MouseListener {

  private SoundBank sb = new SoundBank();

  @Override
  public void mouseClicked(MouseEvent e) {
    requestFocusInWindow();
  }

  @Override
  public void mousePressed(MouseEvent e) {
    /*
     * focus position - mouse pos
     * calculate angle
     */
    double focusX = this.getWidth();
    double focusY = this.getHeight();
    if (focusX < 0 || focusY < 0) {
      return;
    }
    int tilenumX = this.getWidth() / tilesize, tilenumY = this.getHeight() / tilesize;
    double fxp = this.getWidth() / 2 - this.getWidth() % tilesize + tilesize / 2;//focus x in pixels
    double fyp = this.getHeight() / 2 - this.getHeight() % tilesize + tilesize / 2;//focus y in pixels
    double mx = e.getX(), my = e.getY();//mouse coordinates

    double dx = mx - (focusX / 2);
    // Minus to correct for coord re-mapping
    double dy = -(my - (focusY / 2));

    double inRads = Math.atan2(dy, dx);

    // We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12 O'clock
    if (inRads < 0) {
      inRads = Math.abs(inRads);
    } else {
      inRads = 2 * Math.PI - inRads;
    }
    //double angle = Math.toDegrees(inRads);

    double angle = inRads * 128 / Math.PI;//Make a full circle 256 degrees so that it fits within a single byte.
    client.attack(new Double(angle - Byte.MAX_VALUE).byteValue());
    sb.PlaySound("ATTACK_1");
  }

  @Override
  public void mouseReleased(MouseEvent e) {
  }

  @Override
  public void mouseEntered(MouseEvent e) {
  }

  @Override
  public void mouseExited(MouseEvent e) {
  }

  @Override
  public void chatMsg(String player, String msg) {
  }

  @Override
  public void setViewRange(int range) {
    this.vrange = range;
  }

  private class MoveAction extends AbstractAction {

    private int direction;

    public MoveAction(int direction) {
      this.direction = direction;

    }

    @Override
    public void actionPerformed(ActionEvent e) {
      client.move(direction);
      if (direction==0) {
          sb.PlaySound("STAIRS_UP");
      }
    }
  }
  private ClientWorld world;
  private ImageLoader loader;
  private Client client;
  private int tilesize = 32;
  private int vrange = 3;

  public GamePanel(Client client) {
    this.client = client;
    client.addGameListener(this);
    world = client.getWorld();
    this.setFocusable(true);
    loader = new ImageLoader();
    //this.addKeyListener(ih);
    setFocusable(true);
    addMouseListener(this);

    this.getActionMap().put("MoveWest", new MoveAction(Gameworld.WEST));
    this.getActionMap().put("MoveEast", new MoveAction(Gameworld.EAST));
    this.getActionMap().put("MoveNorth", new MoveAction(Gameworld.NORTH));
    this.getActionMap().put("MoveSouth", new MoveAction(Gameworld.SOUTH));
    this.getActionMap().put("Activate", new MoveAction(0));

    this.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "MoveNorth");
    this.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "MoveSouth");
    this.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "MoveWest");
    this.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "MoveEast");
    this.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "MoveNorth");
    this.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "MoveSouth");
    this.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "MoveWest");
    this.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "MoveEast");
    this.getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "Activate");

  }

  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    world = client.getWorld();
    Graphics2D g2 = (Graphics2D) g;
    g2.setColor(Color.BLACK);


    int tilenumX = this.getWidth() / tilesize, tilenumY = this.getHeight() / tilesize;
    int focusX = client.getFocusX();
    int focusY = client.getFocusY();
    if (focusX < 0 || focusY < 0) {
      return;
    }
    int width = this.getWidth();
    int spx = 0;
    Tile tile = null;


    for (int x = focusX - (tilenumX / 2); x < focusX + tilenumX / 2 + 2; x++) {
      int spy = 0;
      for (int y = focusY - tilenumY / 2; y < focusY + (tilenumY) / 2 + 2; y++) {
        tile = world.getTile(x, y);

        if (tile == null || tile.getType().isEmpty()) {
          g2.setColor(Color.BLACK);
          g2.fillRect(spx, spy, tilesize, tilesize);

        } else {
          Image img = loader.load(tile.getType());
          g2.drawImage(img, spx, spy, tilesize, tilesize, null);
        }
        if (tile != null) {
          if (focusX + vrange < x || focusX - vrange > x || focusY + vrange < y
                  || focusY - vrange > y) {
            g2.setPaint(new Color(0, 0, 0, 128));
            g2.fillRect(spx, spy, tilesize, tilesize);
          } else {
            List<GameObject> tc = tile.getContents();
            Iterator<GameObject> it = tc.iterator();
            while (it.hasNext()) {
              GameObject obj = it.next();
              g2.drawImage(loader.load(obj.getType()), spx, spy, tilesize, tilesize, null);
            }
          }
        }


        spy += tilesize;
      }
      spx += tilesize;
    }




  }

  @Override
  public void die() {
  }

  @Override
  public void worldUpdate() {
    this.repaint();
  }

  @Override
  public void gameEnded() {
  }

  @Override
  public void playerUpdate() {
  }
}
